/**
 *
 */
package name.yzhu.wbdata.weibo;

import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.tencent.weibo.constants.OAuthConstants;
import com.tencent.weibo.oauthv2.OAuthV2;
import name.yzhu.common.conf.PropertyConfig;
import name.yzhu.common.net.HttpClientRequest;
import name.yzhu.common.net.SchemeType;
import name.yzhu.common.yaml.YamlItem;
import name.yzhu.wbdata.Constant;
import name.yzhu.wbdata.io.WeiboYamlRow;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONUtils;

/**
 * @author yhzhu
 *
 */
public class TencentWeiboSDK extends AbstractWeiboSDK{
	private static final Log LOG = LogFactory.getLog(TencentWeiboSDK.class);

	private static final String APP_KEY = "qq.app.key";
	private static final String APP_SECRET = "qq.app.secret";
	private static final String ACCESS_TOKEN = "qq.access.token";
	private static final String APP_OPEN_ID = "qq.openid";

	private static final String PULIC_FREQ = "qq.public.freq";
	private static final String FRIEND_FREQ = "qq.friend.freq";

	private OAuthV2 oAuth=new OAuthV2();

	protected String appOpenId;

	private int publicPos = 0;
	private long friendLastPagetime = 0;

	private boolean friendHasNext = true;

	private boolean publicHashNext = true;

	public TencentWeiboSDK(BlockingQueue<YamlItem> queue) {
		super(queue);
		this.weiboType = WeiboType.TENCENT;
	}

	@Override
	public void open(PropertyConfig proCFG) {
		appKey = proCFG.getString(APP_KEY);
		appSecret = proCFG.getString(APP_SECRET);
		accessToken = proCFG.getString(ACCESS_TOKEN);
		appOpenId = proCFG.getString(APP_OPEN_ID);

		oAuth.setClientId(appKey);
		oAuth.setClientSecret(appSecret);
		oAuth.setAccessToken(accessToken);
		oAuth.setOpenid(appOpenId);

		setPublicFreq(Integer.valueOf(proCFG.getString(PULIC_FREQ, String.valueOf(getPublicFreq()))));
		setFriendFeq(Integer.valueOf(proCFG.getString(FRIEND_FREQ, String.valueOf(getPublicFreq()))));
	}

	public String getOpenId() {
		return appOpenId;
	}

	public OAuthV2 getOAuth() {
		return oAuth;
	}

	@Override
	protected boolean checkPublicReqest() {
		 return (!publicHashNext && skippedPublicRequest < 5)?false:true;
	}

	@Override
	protected boolean checkFriendReqest() {
	    return (!friendHasNext && skippedFriendRequest < 15)?false:true;
	}

	@Override
	public String getDataSource() {
		return WeiboType.TENCENT.getType();
	}

	@Override
	public List<YamlItem> publicTimeLine() throws WeiboException {
		HttpClientRequest client = new HttpClientRequest();
		try {
			client.open();
			String url = "http://open.t.qq.com/api/statuses/public_timeline";
			Map<String,String>param = new HashMap<String, String>();
			param.put("format","json");
			param.put("pos", String.valueOf(publicPos));
			param.put("reqnum","100");
			param.put("appkey", getAppKey());

			String content = client.getWebContent(url, param);
			if (content == null) {
				throw new Exception("content is null");
			}
			TencentWeiboObject weibo = parseJson(content);
			if (!weibo.getRet()) {
				throw new WeiboException("errCode: "+weibo.getErrCode()+" errMsg: "+weibo.getMsg());
			}
			if (publicPos == weibo.getPos()){
				publicHashNext = false;
				return null;
			}
			publicPos = weibo.getPos();
			publicHashNext = weibo.isHasNext();

			return weibo.getWeibo();
		} catch (Exception e) {
			LOG.error("Tencent publicTimeLine failed ", e);
			throw new WeiboException(e);
		}
		finally {
			client.close();
		}
	}

	@Override
	public List<YamlItem> friendTimeLine() throws WeiboException {
		HttpClientRequest client = new HttpClientRequest();
		try {
			client.open(SchemeType.HTTPS);
			String url = "https://open.t.qq.com/api/statuses/home_timeline";
			Map<String,String>param = new HashMap<String, String>();
			param.put("format","json");
			param.put("pageflag", "0");
			param.put("pagetime", String.valueOf(friendLastPagetime));
			param.put("reqnum","70");
			param.put("type","0");
			param.put("contenttype","0");
			param.put("oauth_consumer_key", getAppKey());
			param.put("access_token", getAccessToken());
			param.put("openid", getOpenId());
			param.put("oauth_version", OAuthConstants.OAUTH_VERSION_2_A);

			String content = client.getWebContent(url, param);
			if (content == null) {
				throw new Exception("content is null");
			}
			TencentWeiboObject weibo = parseJson(content);
			if (!weibo.getRet()) {
				throw new WeiboException("errCode: "+weibo.getErrCode()+" errMsg: "+weibo.getMsg());
			}
			friendHasNext = weibo.isHasNext();
			if (friendLastPagetime == weibo.getLastPageTime()){
				friendHasNext = false;
				return null;
			}
			friendLastPagetime = weibo.getLastPageTime();

			return weibo.getWeibo();
		} catch (Exception e) {
			LOG.error("Tencent friendTimeLine failed ", e);
			throw new WeiboException(e);
		}
		finally {
			client.close();
		}
	}

	private TencentWeiboObject parseJson(String content) throws WeiboException {
		try {
			TencentWeiboObject obj = new TencentWeiboObject();
			obj.setRet(false);
			JSONObject json = JSONObject.fromObject(content);
			if (JSONUtils.isNull(json)) {
				LOG.error("json is null "+ content);
				return obj;
			}
			obj.setRet(json.getInt("ret")==0?true:false);
			obj.setErrCode(json.getInt("errcode"));
			obj.setMsg(json.getString("msg"));
            if (!obj.getRet())
            	return obj;
            if (obj.getMsg().equals("have no tweet")){
            	obj.setHasNext(false);
            	return obj;
            }

            if (!json.has("data")){
            	LOG.warn("there is no data field in the json: "+content);
            	return obj;
            }
			JSONObject data = json.getJSONObject("data");
			if (data.has("pos"))
			   obj.setPos(data.getInt("pos"));
			obj.setHasNext(data.getInt("hasnext")==0?true:false);

			JSONArray info = data.getJSONArray("info");
			LOG.debug("there are "+info.size()+" items which are requested");
			List<YamlItem> list = new ArrayList<YamlItem>(info.size());
			for(int i=0; i<info.size(); ++i){
				JSONObject jso = info.getJSONObject(i);
				try {
					YamlItem yaml = new WeiboYamlRow();
					obj.setLastPageTime(jso.getLong("timestamp"));
					Calendar calendar = Calendar.getInstance(Locale.CHINA);
					calendar.setTimeInMillis(obj.getLastPageTime() * 1000);
					String dt = name.yzhu.common.Constant.TIMESTAMP_FORMAT.format(calendar.getTime());
					yaml.put(name.yzhu.common.Constant.YAML_FIELD_DATE, dt);
					yaml.put(name.yzhu.common.Constant.YAML_FIELD_CONTENT, jso.getString("text"));
					yaml.put(name.yzhu.common.Constant.YAML_FIELD_AUTHOR, jso.getString("name"));

					yaml.put(Constant.YAML_FIELD_WEIBO_ID, jso.getString("id"));
					yaml.put(Constant.YAML_FIELD_WEIBO_ORIGINAL_TEXT, jso.getString("origtext"));
					yaml.put(Constant.YAML_FIELD_WEIBO_FORWARD_COUNT, jso.getString("count"));
					yaml.put(Constant.YAML_FIELD_WEIBO_CONMENT_COUNT, jso.getString("mcount"));
					yaml.put(Constant.YAML_FIELD_WEIBO_SOURCE_NAME, jso.getString("from"));
					yaml.put(Constant.YAML_FIELD_WEIBO_SOURCE_URL,
							URLDecoder.decode(jso.getString("fromurl"), name.yzhu.common.Constant.UTF_8_STRING));
					yaml.put(Constant.YAML_FIELD_WEIBO_USER_NICK_NAME, jso.getString("nick"));

					list.add(yaml);
				}
				catch(JSONException e){
					LOG.error(jso.toString(), e);
					throw new WeiboException(jso.toString(), e);
				}
			}
			LOG.info(obj);
			obj.setWeibo(list);
			return obj;
		}
		catch(Exception e){
			LOG.error(content, e);
			throw new WeiboException(e);
		}
	}

	static class TencentWeiboObject{
		boolean ret;
		String msg;
		long lastPageTime;
		int errCode;
		int pos;
		boolean hasNext;
		List<YamlItem> weibo;
		public boolean getRet() {
			return ret;
		}
		public void setRet(boolean ret) {
			this.ret = ret;
		}
		public String getMsg() {
			return msg;
		}
		public void setMsg(String msg) {
			this.msg = msg;
		}
		public int getErrCode() {
			return errCode;
		}
		public void setErrCode(int errCode) {
			this.errCode = errCode;
		}
		public int getPos() {
			return pos;
		}
		public void setPos(int pos) {
			this.pos = pos;
		}
		public boolean isHasNext() {
			return hasNext;
		}
		public void setHasNext(boolean hasNext) {
			this.hasNext = hasNext;
		}
		public List<YamlItem> getWeibo() {
			return weibo;
		}
		public void setWeibo(List<YamlItem> weibo) {
			this.weibo = weibo;
		}
		public long getLastPageTime() {
			return lastPageTime;
		}
		public void setLastPageTime(long l) {
			this.lastPageTime = l;
		}

		@Override
		public String toString() {
			return "TencentWeiboObject [ret=" + ret + ", msg=" + msg
					+ ", lastPageTime=" + lastPageTime + ", errCode=" + errCode
					+ ", pos=" + pos + ", hasNext=" + hasNext + ", weibo="
					+ weibo + "]";
		}

	}
}
